﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

using BackupLibrary;
using HelperLibrary;
using MasterLibrary.Logging;
using MasterLibrary.Windows.Forms;
using MasterLibrary.Windows.Forms.Aero;

namespace Prometheus
{
    public partial class MainForm : WizardForm
    {
        private ApplicationLogger logger;
        private BackupClass backupClass;
        private BackupContainer backupContainer;

        #region Events

        public event EventHandler Minimized;
        private void OnMinimized()
        {
            EventHandler ev = Minimized;
            if (ev != null) ev(this, EventArgs.Empty);
        }

        public event EventHandler BackupCompleted;
        private void OnBackupCompleted()
        {
            EventHandler ev = BackupCompleted;
            if (ev != null) ev(this, EventArgs.Empty);
        }

        #endregion

        public MainForm()
        {
            InitializeComponent();

            // initialize log system
            this.logger = ApplicationLogger.Singleton();

            // check updates
            this.updateController.checkForUpdatesAsync();
            this.updateController.updateFound += new updateSystemDotNet.updateFoundEventHandler(updateController_updateFound);

            // initiliaze backup classes
            this.backupClass = new BackupClass();
            this.backupContainer = backupClass.LoadBackupContainer();

            // initiliaze wizard
            this.Pages.Add(new wzStart(), "Startpage", null, null);
            this.Pages.Add(new wzBackup(), "DoBackup", null, null);
            this.Pages.Add(new wzBackupComplete(), "BackupComplete", null, null);
            this.Pages.Add(new wzSettings(), "Settings", "Startpage", null);
            this.Pages.Add(new wzSettingsData(this.backupContainer), "SettingsData", "Settings", null);
            this.Pages.Add(new wzSettingsDataExclude(this.backupContainer), "SettingsDataExclude", "Settings", null);
            this.Pages.Add(new wzSettingsTime(), "SettingsTime", "Settings", null);
            this.Pages.Add(new wzSettingsGlobal(), "SettingsGlobal", "Settings", null);

            // load startpage
            this.LoadPage("Startpage");
        }

        // override minimize scenario to minimize in tray
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == (Int32)WindowsMessages.WM_SYSCOMMAND && m.WParam == (IntPtr)61472)
            {
                if (!backgroundWorker.IsBusy)
                {
                    this.OnMinimized();
                    return;
                }
            }
            if (m.Msg == (Int32)WindowsMessages.WM_SYSCOMMAND && m.WParam == (IntPtr)61488)
            {
                // do own miximize code
            }
            base.WndProc(ref m);
        }

        // load settings page
        private void btnSettings_Click(object sender, EventArgs e)
        {
            this.LoadPage("Settings");
        }
        private void picLogo_Click(object sender, EventArgs e)
        {
            using (AboutForm aboutForm = new AboutForm())
            {
                aboutForm.ShowDialog();
            }
        }
        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.backupClass.SendCancelEvent();
        }

        #region Update Block

        void updateController_updateFound(object sender, updateSystemDotNet.appEventArgs.updateFoundEventArgs e)
        {
            if (this.updateController.showUpdateDialog(this) == DialogResult.OK && this.updateController.downloadUpdatesDialog(this) == DialogResult.OK)
                this.updateController.applyUpdate();
        }

        #endregion

        #region WizardPage Events
        // perform special actions on different pages
        private void MainForm_WizardPageChanged(object sender, WizardPageChangedEventArgs e)
        {
            if (e.NewPage.Key.Equals("DoBackup"))
            {
                this.btnSettings.Visible = false;
                this.btnSettings.Enabled = true;
                this.btnExit.Visible = false;
                this.btnExit.Enabled = true;
                this.btnCancel.Visible = true;
                this.btnCancel.Enabled = true;
                SetTaskBarProgressState(ThumbnailProgressState.Normal);
                this.backgroundWorker.RunWorkerAsync();
            }
            else if (e.NewPage.Key.Equals("Startpage"))
            {
                this.btnSettings.Visible = true;
                this.btnSettings.Enabled = true;
                this.btnExit.Visible = true;
                this.btnExit.Enabled = true;
                this.btnCancel.Visible = false;
                this.btnCancel.Enabled = false;
                SetTaskBarProgressState(ThumbnailProgressState.NoProgress);
            }
            else if (e.NewPage.Key.Equals("BackupComplete"))
            {
                this.btnSettings.Visible = true;
                this.btnSettings.Enabled = false;
                this.btnExit.Visible = true;
                this.btnExit.Enabled = false;
                this.btnCancel.Visible = false;
                this.btnCancel.Enabled = false;
                SetTaskBarProgressState(ThumbnailProgressState.NoProgress);
            }

            if (e.NewPage.Key.Equals("SettingsData"))
            {
                wzSettingsData wz = this.CurrentPage as wzSettingsData;

                if (wz != null)
                {
                    wz.ReloadBackupCollection();
                    wz.ContainerChanged += new EventHandler<wzSettingsDataChangedEventArgs>(wzSettingsData_ContainerChanged);
                }
            }
            if (e.NewPage.Key.Equals("SettingsDataExclude"))
            {
                wzSettingsDataExclude wz = this.CurrentPage as wzSettingsDataExclude;

                if (wz != null)
                {
                    wz.ReloadBackupCollection();
                    wz.ContainerChanged += new EventHandler<wzSettingsDataExcludeChangedEventArgs>(wzSettingsDataExclude_ContainerChanged);
                }
            }
            if (e.NewPage.Key.Equals("SettingsGlobal"))
            {
                wzSettingsGlobal wz = this.CurrentPage as wzSettingsGlobal;

                if (wz != null)
                {
                    wz.SearchForUpdates += new EventHandler(wzSettingsGlobal_SearchForUpdates);
                }
            }
            if (e.NewPage.Key.Equals("SettingsTime"))
            {
                wzSettingsTime wz = this.CurrentPage as wzSettingsTime;

                if (wz != null)
                {
                    wz.ReloadConfiguration();
                }
            }
        }

        // settings data event
        private void wzSettingsDataExclude_ContainerChanged(object sender, wzSettingsDataExcludeChangedEventArgs e)
        {
            this.backupContainer = e.Container;
            new Thread(new ThreadStart(SaveBackupConfiguration)).Start();
        }
        private void wzSettingsData_ContainerChanged(object sender, wzSettingsDataChangedEventArgs e)
        {
            this.backupContainer = e.Container;
            new Thread(new ThreadStart(SaveBackupConfiguration)).Start();
        }
        private void SaveBackupConfiguration()
        {
            try
            {
                this.backupClass.SaveBackupContainer(this.backupContainer);
            }
            catch
            {
                //TODO: log message
            }
        }

        void wzSettingsGlobal_SearchForUpdates(object sender, EventArgs e)
        {
            this.updateController.updateInteractive(this);
        }
        #endregion
        
        #region Background Worker

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            this.backupClass.UpdateProgress += new EventHandler<BackupEventArgs>(backupClass_UpdateProgress);
            this.backupClass.UpdateFileProgress += new EventHandler<BackupEventArgs>(backupClass_UpdateFileProgress);
            BackupState result = this.backupClass.CreateBackup(this.backupContainer, this);

            this.backgroundWorker.ReportProgress(100, new string[] { "2", "Datensicherung abgeschlossen." });

            if (result == BackupState.OK)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new dLoadCompletePage(LoadCompletePage));

                }
            }
            else if (result == BackupState.Error)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new dLoadCompletePage(LoadErrorPage));
                }
            }
            else if (result == BackupState.Canceled)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new dLoadCompletePage(LoadCancelPage));
                }
            }
        }

        private void backupClass_UpdateFileProgress(object sender, BackupEventArgs e)
        {
            this.backgroundWorker.ReportProgress((int)((double)e.ActualCopiedSize / (double)(e.ActualFilesize) * 100), new string[] { "1", e.ActualFilename });
        }

        private void backupClass_UpdateProgress(object sender, BackupEventArgs e)
        {
            this.backgroundWorker.ReportProgress((int)((double)e.ActualFileIndex / (double)(e.TotalFileCount) * 100), new string[] { "0", e.SourcePath });
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            wzBackup wzPage = this.CurrentPage as wzBackup;

            if (wzPage != null)
            {
                string[] state = (string[])e.UserState;

                if (state[0] == "0")
                {
                    wzPage.SetOverallProgress(e.ProgressPercentage, state[1]);
                }
                else if (state[0] == "2")
                {
                    wzPage.SetOverallProgress(e.ProgressPercentage, state[1]);
                    wzPage.SetProgress(e.ProgressPercentage, "");
                }
                else
                {
                    wzPage.SetProgress(e.ProgressPercentage, state[1]);
                }
            }
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.OnBackupCompleted();
        }

        private delegate void dLoadCompletePage();
        private void LoadCompletePage()
        {
            this.LoadPage("BackupComplete");
            this.Pages.Remove("DoBackup");
            this.Pages.Add(new wzBackup(), "DoBackup", null, null);
        }
        private void LoadErrorPage()
        {
            this.LoadPage("BackupComplete");
            
            wzBackupComplete wz = this.CurrentPage as wzBackupComplete;
            if (wz != null)
            {
                wz.SetErrorState();
            }

            this.Pages.Remove("DoBackup");
            this.Pages.Add(new wzBackup(), "DoBackup", null, null);
        }
        private void LoadCancelPage()
        {
            this.LoadPage("BackupComplete");

            wzBackupComplete wz = this.CurrentPage as wzBackupComplete;
            if (wz != null)
            {
                wz.SetCancelState();
            }

            this.Pages.Remove("DoBackup");
            this.Pages.Add(new wzBackup(), "DoBackup", null, null);
        }
        
        #endregion

        #region Shutdown Methods
        // perform application shutdown
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (backgroundWorker.IsBusy)
            {
                e.Cancel = true;
                this.ShowBorderMessage(BorderMessageIcon.Exclamation_White, "Das Beenden ist nicht möglich... Es wird gerade eine Sicherung ausgeführt!", 3);
            }
            else
            {
                this.ApplicationExit();
            }
        }
        private void btnExit_Click(object sender, EventArgs e)
        {
            this.ApplicationExit();
        }
        private void ApplicationExit()
        {
            this.backupClass.SaveBackupContainer(this.backupContainer);
            Globals.SaveConfiguration(Globals.appConfig);

            this.logger.Shutdown();

            Application.Exit();
        }
        #endregion
    }
}
